package controllers

import java.io.File
import java.sql.Date
import java.util.UUID

import DB._
import akka.actor.{ActorIdentity, Identify}
import akka.pattern._
import akka.util.Timeout
import com.typesafe.config.ConfigFactory
import common.Tool._
import common._
import play.api.Logger
import play.api.Play.current
import play.api.libs.Files.TemporaryFile
import play.api.libs.concurrent.Akka
import play.api.mvc._
import common.JedisCacheKeys._
import tools._

import scala.concurrent._
import scala.concurrent.duration._

/**
 * Created by 林 on 14-4-8.
 */
class BaseController extends Controller {
  //全局变量定义
  lazy val conf = ConfigFactory.load()
//  private var lastSettingMap = Map[String, String]()
  implicit val timeout = Timeout(60 seconds)
  def fs=getSettingCacheObject("aliAccessId", "aliAccessKey","aliOssBucket","aliOssaliyunEndpoint","aliOssHost")(list => new Aliyun(list(0), list(1),list(2),list(3),list(4)))

  def cloopenSms = getSettingCacheObject("cloopenAccount", "cloopenToken", "cloopenAppid")(list => new Cloopen(list(0), list(1), list(2)))

  //直接封装包含用户是否登录的消息以及当前时间
  implicit def setting = {
    getSettingMap //++ getSessionMap + ("time" -> System.currentTimeMillis().toString)
  }

  def uuid=UUID.randomUUID().toString.replace("-","")

  //标识一个请求是否有登录的

  val ajaxOk = Map("code" -> 200, "msg" -> "ok","t"->System.currentTimeMillis()/1000).toJson

  def articlePath=setting("articlePath")
  def userArticlePath=setting("userArticlePath")
  def outArticlePath=setting("outArticlePath")
  def viewArticlePath=setting("viewArticlePath")

  def getActor(path: String) = {
    val actorFuture = Akka.system.actorSelection(path)
    val asker = new AskableActorSelection(actorFuture)
    val fut = asker.ask(new Identify(1))
    val ident = Await.result(fut, timeout.duration).asInstanceOf[ActorIdentity]
    ident.getRef
  }

  //Actors
  lazy val  taskServer=getActor("/user/task_server_actor")
  lazy val  dbTaskServer=getActor("/user/db_task_server_actor")
  lazy val  cacheServer=getActor("/user/cache_server_actor")

  //普通方法 ，父类里面拦截掉所有的子类方法干些屌爆的事情
  object JsAction extends ActionBuilder[Request] {
    def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
      try{
        block(request).map(_.withHeaders("Cache-Control"->"no-cache","Content-Type" -> "application/json; charset=utf-8"))
      }catch {
        case e: Exception =>
          e.printStackTrace()
          Future.successful(Ok(Map("code" -> 500, "msg" -> e.getMessage).toJson).withHeaders("Cache-Control"->"no-cache","Content-Type" -> "application/json; charset=utf-8"))
      }
    }
  }

  //管理登录方法
  object AdminAction extends ActionBuilder[Request] {
    def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
      val admin = request.session.get("admin").getOrElse("")
      val id = request.session.get("adminid").getOrElse("0")
      request.session.get("adminName") map {
        adminName =>
          def parseRule(path:String)={
            val namerules=toBean(JedisTool.useJedis(_.hget("admin_roles",id).getOrElse("[]")),classOf[List[String]])
            val kvs=namerules.map(nr=>nr.split(",")(0)->nr.split(",")(1)).toMap
            val directComp=kvs.filter(_._2==path)
            if(!directComp.isEmpty){
              (true,directComp.head._1)
            }else{
              val idRules=kvs filter(_._2.contains("{")) map (kv=> kv._1 ->kv._2.replace("{id}","[\\w]+"))
              val v=idRules filter(ir=>ir._2.r.pattern.matcher(path).matches)
              if(!v.isEmpty){
                (true,v.head._1)
              }else{
                (false,"")
              }
            }
          }
          val rule=(request.method+":"+request.path).toLowerCase()
          val (pass,name)=parseRule(rule)
          if(pass){
            //发送管理员操作日志
            Future{
              Tool.safe {
                new AdminModifyLog(uuid, request.session.get("adminid").get.toInt, adminName, name, request.method, request.path, ip(request), new Date(System.currentTimeMillis())).insertWithId()
              }
            }
            try{
              block(request)
            }catch {
              case e: Exception => e.printStackTrace()
                Future.successful(InternalServerError(Map("code" -> 500, "msg" -> e.getMessage).toJson))
            }
          }else{
            Future.successful(Status(403)(Map("code" -> 403, "msg" -> "无权操作，请联系超级管理员分配权限","t"->System.currentTimeMillis()/60000).toJson))
          }
      } getOrElse {
        Future.successful(Status(401)(Map("code" -> 401, "msg" -> "登录已过期，请重新登录","t"->System.currentTimeMillis()/60000).toJson))
      }
    }
  }

  object Action extends ActionBuilder[Request] {
    def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
      try{
        block(request)
      }catch {
        case e: Exception =>
          e.printStackTrace()
          Future.successful(Ok(views.html.error(e.getMessage)))
      }
    }
  }
  //管理登录方法
  object UserAction extends ActionBuilder[Request] {
    def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
      val id = request.session.get("uid").getOrElse("0")
      request.session.get("uid") map {
        name =>
            try{
              block(request).map(_.withHeaders("Cache-Control"->"no-cache","Content-Type" -> "application/json; charset=utf-8"))
            }catch {
              case e: Exception => e.printStackTrace()
                Future.successful(Ok(Map("code" -> 500, "msg" -> e.getMessage).toJson).withHeaders("Cache-Control"->"no-cache","Content-Type" -> "application/json; charset=utf-8"))
            }
      } getOrElse {
        Future.successful(Status(401)(Map("code" -> 401, "msg" -> "登录已过期，请重新登录","t"->System.currentTimeMillis()/1000).toJson))
      }
    }
  }

  def jsonListRequest(data:List[AnyRef],pageNum:Int,allCount:Int, pageSize:Int): play.api.mvc.Result = {
    Ok(Map("code" -> 200, "msg" -> "成功",
      "list" -> data, "page" ->pageNum.toString(),"pageNum" ->pageNum, "pageSize" ->pageSize.toString(),"total" ->allCount,"allCount" ->allCount,"allPage"->(allCount / pageSize + 1),"t"->System.currentTimeMillis()/1000).toJson).withHeaders("Cache-Control"->"no-cache","Content-Type" -> "application/json; charset=utf-8")
  }

  def errorPage = JsAction {
    implicit request =>
      InternalServerError("系统错误")
  }

  //发送邮件给开发组
  def sendStackTrace(e:Throwable,msg:String)={
    Logger.info("find send out error mail",e)
  }

  def showError( message: String = "系统错误") = {
    Ok(views.html.error(message))
  }

  def getPage(implicit request: Request[AnyContent]) = (request.getQueryString("page").getOrElse("1").toInt,request.getQueryString("pageSize").getOrElse("10").toInt)

  def getBody(data: String*)(implicit request: Request[AnyContent]) = {
    if (request.body.asFormUrlEncoded.isEmpty) {
      data map (v => "") toList
    } else data map (s => request.body.asFormUrlEncoded.get.getOrElse(s, List(""))(0)) toList
  }

  def getQuery(data: String*)(implicit request: Request[AnyContent]) = {
    if (request.queryString.isEmpty) {
      data map (v => "") toList
    } else data map (s => request.getQueryString(s).getOrElse("")) toList
  }

  //先从query里面取，取不到从body里面取
  def getParam(data: String*)(implicit request: Request[AnyContent]) = {
    data map (s => request.getQueryString(s).getOrElse {
      if(request.body.asFormUrlEncoded.isEmpty) ""
      else request.body.asFormUrlEncoded.get.getOrElse(s, List(""))(0)
    }) toList
  }


  def ip(implicit request: Request[Any])={
    if (request.headers.get("x-forwarded-for").isEmpty) {
      (request.remoteAddress).trim
    } else {
      request.headers.get("x-forwarded-for").get
    }
  }

  def base64(data:Array[Byte]):String={
    if(isEmpty(data)){
      null
    }else {
      new String(Base64.encode(data))
    }
  }
  def unBase64(data:String)={
    if(isEmpty(data)){
      null
    }else {
      Base64.decode(data.getBytes)
    }
  }
  def tempFileToArray(tf:TemporaryFile):Array[Byte]={
    val file=new File("/tmp/"+System.currentTimeMillis())
    tf.moveTo(file,true)
    fs.File2Byte(file)
  }
  //检查并启动条件限制
  def keyLimit(key: String, count: Int, express: Int) = {
    val rk = "key_limit_" + key
    val v = JedisTool.useJedis(_.get(rk))
    if (v.isDefined && v.get.safeInt >= count) {
      throw new RequstLimitExcepiton
    } else {
      val setv = if (v.isEmpty) 0 else v.get.toInt
      JedisTool.useJedis(_.set(rk, setv + 1))
      JedisTool.useJedis(_.expire(rk, express))
    }
  }
  //取消条件限制
  def keyUnlimit(key: String) = {
    JedisTool.useJedis(_.del("key_limit_" + key))
  }
  def safe(f: => Result)={
    try{
      f
    }catch{
      case e: Exception => InternalServerError(Map("code" -> 500, "msg" -> e.getMessage).toJson)
    }
  }

//  Post跳转
  def redirectPage(title:String,postUrl:String,data:Map[String,String],actionName:String="跳转中")={
    Ok(views.html.redirectPage(title,postUrl,actionName,data))
 }

  def getQueryParam(m: Map[String, Any]) = {
    val data = m filter (v => !isEmpty(v._2))
    val where = data map (_._1) mkString (" and ")
    val param = data map (_._2.toString) toList

    (where, param)
  }

  def getQueryParambyGet(names:String*)(implicit request: Request[AnyContent]) = {
    val datas = names map (k=> (k+"=?") -> getQuery(k)(request)(0))  filter (v => !isEmpty(v._2)) toMap

    getQueryParam(datas)
  }

  def getQueryParambyPost(names:String*)(implicit request: Request[AnyContent]) = {
    val datas = names map (k=> (k+"=?") -> getBody(k)(request)(0))  filter (v => !isEmpty(v._2)) toMap

    getQueryParam(datas)
  }

  /**
   * 根域名
    *
    * @return
   */
  def baseUrl = s"""${setting("mainDomain")}"""

  def safe[T](msg: String)(f: => T): T = {
    try {
      f
    } catch {
      case e: Throwable =>
        Logger.error(msg + e.getMessage)
        null.asInstanceOf[T]
    }
  }

  def getCacheDatas(list:List[String],key:String):List[Any]={
    list.toSet[String].map(id=> getCache(key+id)).filter(_.isDefined).map(_.get).toList
  }
  def getCacheData(id:String,key:String)={
    getCache(key+id)
  }
}
